#region License
// Copyright (c) 2005-2012, CellAO Team
// 
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//     * Neither the name of the CellAO Team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

#region Usings...
using Config = TSW.Core.Config.ConfigReadWrite;

#endregion

namespace GameWorld
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Timers;

    using TSW.Core;

    using Cell.Core;

    using ComponentAce.Compression.Libs.zlib;


    using Timer = System.Timers.Timer;

    /// <summary>
    /// 
    /// </summary>
    public class Client : ClientBase
    {
        #region Constructors
        /// <summary>
        /// 
        /// </summary>
        /// <param name="srvr"></param>
        public Client(Server srvr)
            : base(srvr)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        public Client()
            : base(null)
        {
        }
        #endregion

        #region Needed overrides
        /// <summary>
        /// 
        /// </summary>
        /// <param name="numBytes"></param>
        protected override void OnReceive(int numBytes)
        {
            byte[] packet = new byte[numBytes];
            Array.Copy(this.m_readBuffer.Array, this.m_readBuffer.Offset, packet, 0, numBytes);
            PacketReader reader = new PacketReader(packet);

            // TODO: make check here to see if packet starts with 0xDFDF
            reader.ReadBytes(2);

            // Packet type
            short type = reader.PopShort();

            // Unknown?
            reader.PopShort();

            // Packet Length
            reader.PopShort();

            // Sender
            reader.PopInt();

            // Receiver
            reader.PopInt();

            // PacketID
            int id = reader.PopInt();

            switch (type)
            {
                case 0x01: // SystemMessage
                    {
                        break;
                    }
                case 0x05: // TextMessage
                    {
                        break;
                    }
                case 0x0A: // N3Message
                    {
                        break;
                    }
                case 0x0B: // PingMessage
                    {
                        break;
                    }
                case 0x0E: // OperatorMessage
                    {
                        break;
                    }
                default: // UnknownMessage
                    {
                        // TODO: Handle Unknown Messages
                        break;
                    }
            }
            reader.Finish();
        }
        #endregion

        #region Misc overrides
        /// <summary>
        /// 
        /// </summary>
        /// <param name="packet"></param>
        public override void Send(byte[] packet)
        {
            // 18.1 Fix
           // byte[] pn = BitConverter.GetBytes(this.packetNumber++);
            //packet[0] = pn[1];
           // packet[1] = pn[0];

            base.Send(packet);
        }

        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="packet"></param>
        //public void SendCompressed(byte[] packet)
        //{
        //    int tries = 0;
        //    Boolean done = false;
        //    // 18.1 Fix
        //   // byte[] pn = BitConverter.GetBytes(this.packetNumber++);
        //   // packet[0] = pn[1];
        //   // packet[1] = pn[0];
        //    while ((!done) && (tries < 3))
        //    {
        //        try
        //        {
        //        //    done = true;
        //        //    if (!this.zStreamSetup)
        //        //    {
        //        //        // Create the zStream
        //        //        this.netStream = new NetworkStream(this.TcpSocket);
        //        //        this.zStream = new ZOutputStream(this.netStream, zlibConst.Z_BEST_COMPRESSION);
        //        //        this.zStream.FlushMode = zlibConst.Z_SYNC_FLUSH;
        //        //        this.zStreamSetup = true;
        //        //    }

        //        //    this.zStream.Write(packet, 0, packet.Length);
        //        //    this.zStream.Flush();
        //        //}
        //        //catch (Exception)
        //        //{
        //        //    tries++;
        //        //    done = false;
        //        //    this.Server.DisconnectClient(this);
        //        //    return;
        //        //}
        //    }
        //    if (!done)
        //    {
        //        // Old Code, probably not needed anymore
        //        /*
        //        Console.ForegroundColor = ConsoleColor.Red;
        //        Console.WriteLine("Exception caught: "+Program.zoneServer.Clients.Count+" Clients active, Startup: "+Character.startup.ToString()+" DDT: "+Character.dontdotimers.ToString()+" Port: "+TcpPort);
        //        Console.WriteLine(Debughelpers.PacketToHex(packet));
        //        Console.WriteLine();
        //        Console.ResetColor();
        //        FileInfo t = new FileInfo("exception.log");
        //        if (t.Exists == true)
        //        {
        //            TextWriter tex = new StreamWriter(t.OpenWrite());
        //            tex.WriteLine("Date/Time: " + DateTime.Now.ToString());
        //            tex.WriteLine(" ");
        //            tex.WriteLine("Dump:");
        //            tex.WriteLine(Debughelpers.PacketToHex(packet));
                    
        //            tex.Flush();
        //            tex.Close();
        //            tex = null;
        //            t = null;
        //        }
        //        else
        //        {
        //            StreamWriter sw = t.CreateText();
        //            sw.WriteLine("Date/Time: " + DateTime.Now.ToString());
        //            sw.WriteLine(" ");
        //            sw.WriteLine("Data: " + BitConverter.ToString(packet).Replace('-', ' '));
        //            sw.WriteLine(" ");
        //            sw.Write(sw.NewLine);
        //            sw.Flush();
        //            sw.Close();
        //            sw = null;
        //            t = null;
        //        }
        //         */
        //    }
        //}

        /// <summary>
        /// 
        /// </summary>
        public override void Cleanup()
        {
            base.Cleanup();
            //AH FINALLY, Man, get some NORMAL names (OnDisconnect maybe?).
            bool foundnextclient = false;
            foreach (Client c in this.Server.Clients)
            {
    
            }
            if (!foundnextclient)
            {

            }
        }
        #endregion

        #region Our own stuff
        /// <summary>
        /// 
        /// </summary>
        //TODO: Do we need this still or get rid of it?
        //public UInt16 packetNumber = 1;

        private bool zStreamSetup;

        private NetworkStream netStream;

        private ZOutputStream zStream;

        // Core Timers Enable Variable
        private bool SkipCoreTimers = true;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="MsgCategory"></param>
        /// <param name="MsgNum"></param>
        /// <returns></returns>
        /// 

        #region Add Core Timer
        //public void AddCoreTimer(int strain, DateTime time, TSWFunctions aof)
        //{
        //    TSWTimers newCoretimer = new TSWTimers();
        //    newCoretimer.Function = aof;
        //    newCoretimer.Timestamp = time;
        //    newCoretimer.Strain = strain;
        //    this.CoreTimers.Add(newCoretimer);
        //}
        #endregion

        #region Purge Core Timer
        public void PurgeCoreTimer(int strain)
        {

        }
        #endregion

        #region Process Core Timers
        public void processCoreTimers(DateTime _now)
        {

        }
        #endregion

        public bool SendFeedback(int MsgCategory, int MsgNum)
        {
            PacketWriter _writer = new PacketWriter();
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Text"></param>
        /// <returns></returns>
        public bool SendChatText(string Text)
        {
            PacketWriter _writer = new PacketWriter();

            return true;
        }


        private static Timer LogoutTimer = new Timer();

        // Starts a 30 second timer
        public void startLogoutTimer()
        {
            LogoutTimer = new Timer(30000);
            LogoutTimer.Elapsed += this.LogOut;
            LogoutTimer.Enabled = true;
        }

        // Called after 30 second timer elapses
        private void LogOut(Object sender, ElapsedEventArgs e)
        {
            this.Server.DisconnectClient(this);
        }

        /* Called from CharacterAction class in case of 'stop logout packet'
         * Stops the 30 second timer and sends 'stop logout packet' back to client
        */

        public void CancelLogOut()
        {
            LogoutTimer.Enabled = false;
            PacketWriter stopLogout = new PacketWriter();
        }

        /* Called from CharacterAction class in case of 'stand' (0x57)
         * Sends Stand packet back to client
         * In case of logout CancelLogOut (above) stops it.
        */

        public void StandCancelLogout()
        {
            PacketWriter standUp = new PacketWriter();
        }
        #endregion
    }
}